package main

import (
	"fmt"
	"iot-base/common/cache"
	"iot-base/common/config"
	"iot-base/common/custom"
	"iot-base/common/dbconn"
	"iot-base/common/dbobj"
	"iot-base/common/logger"
	"iot-base/common/monitor"
	"iot-base/common/token"
	"iot-base/common/webapi"
	"iot-base/tm/common/alarmapi"
	"iot-base/tm/common/dataapi"
	_ "iot-base/tm/common/dbinit"
	"iot-base/tm/common/fileapi"
	"iot-base/tm/common/maintain"
	"iot-base/tm/common/picapi"
	"iot-base/tm/common/serviceapi"
	"iot-base/tm/common/stateapi"
	"iot-base/tm/common/superadmin"
	"iot-base/tm/common/systemapi"
	"iot-base/tm/common/templateapi"
	"iot-base/tm/common/thingapi"

	"gorm.io/gorm"

	"errors"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	//"iot-base/common/tunnel/csvr"

	"github.com/gin-gonic/gin"
)

type edgeInfo struct {
	LocalCfg  thingapi.Cfg `json:"local_cfg"`
	StationID string       `json:"station_id"`
}

func createByEdge(c *gin.Context) {
	edgeID := c.Param("edgeID")

	var edge edgeInfo
	if err := c.ShouldBindJSON(&edge); err != nil {

		webapi.SendError(err.Error(), webapi.DBError, c)
		return
	}
	err := createByEdgeImpl(edgeID, &edge)
	if err == nil {
		webapi.SendOK(c)
	} else {
		webapi.SendError(err.Error(), -1, c)
	}

}

func createByEdgeImpl(edgeID string, pCfg *edgeInfo) error {

	for _, model := range pCfg.LocalCfg.Models {
		var omodel dbobj.TModel
		err := dbconn.DBConnection.Where("uid=?", model.UID).First(&omodel).Error
		if dbconn.IsNotFound(err) {
			dbconn.DBConnection.Create(&model)
		}

	}
	return dbconn.DBConnection.Transaction(func(tx *gorm.DB) error {

		stationId := pCfg.StationID
		if stationId != "" {
			var station dbobj.Thing
			station.UID = stationId
			err := tx.Model(&dbobj.Thing{}).First(&station).Error

			var stations []dbobj.Station
			if err == nil {

				for _, pThing := range pCfg.LocalCfg.Things {
					isExist := cache.IsModelExists(pThing.PThing.ModelID)
					if !isExist {
						continue
					}
					tx.Save(&pThing.PThing)
					/*if pThing.StationID == "" {
						pThing.StationID = stationId
						pThing.ParentStationID = stationId
					}*/
					if pThing.PThing.IsStation {

						var curStation dbobj.Station
						curStation.UID = pThing.PThing.UID
						curStation.SName = pThing.PThing.SName
						if pThing.ParentStationID == "" {
							pThing.ParentStationID = stationId
							curStation.ParentID = stationId
							tx.Save(&curStation)
						} else {
							var cst dbobj.Station
							cst.UID = pThing.PThing.UID
							cst.SName = pThing.PThing.SName
							cst.ParentID = pThing.ParentStationID
							stations = append(stations, cst)
						}
					} else {
						if pThing.StationID == "" {
							pThing.StationID = stationId
						}
					}
				}
				for _, st := range stations {
					parentID := st.ParentID
					var stationList []dbobj.Station
					for {
						if parentID == "" || parentID == stationId {
							break
						}
						for j, stp := range stations {
							if stp.UID == parentID {
								stationList = append(stationList, stp)
								stations = append(stations[:j], stations[j+1:]...)
								parentID = stp.ParentID
							}
						}
					}
					for _, ss := range stationList {
						tx.Save(&ss)
					}
				}
				for _, pThing := range pCfg.LocalCfg.Things {
					isExist := cache.IsModelExists(pThing.PThing.ModelID)
					if !isExist {
						continue
					}
					if !pThing.PThing.IsStation {
						var ts dbobj.ThingStation
						err := tx.Where("thing_id=?", pThing.PThing.UID).First(&ts).Error
						ts.ThingID = pThing.PThing.UID
						ts.StationID = pThing.StationID
						ts.ModelID = pThing.PThing.ModelID
						ts.SNO = pThing.No
						if err == nil {
							tx.Save(&ts)
						} else {
							tx.Create(&ts)
						}

					}
				}

			}
			return err
		}
		return errors.New("create error")

	})

}

func main() {
	logger.Log.Warn("---------TM in Cloud---------running----------")
	//go csvr.BeginSvr(39999)
	author := token.AuthMiddleware()
	r, api, cfg := thingapi.InitThing(author)
	try := r.Group("/others/")
	try.GET("tryHeart", func(c *gin.Context) {
		c.String(http.StatusOK, "iot-base a connection to the endless world")
	})
	systemapi.InitAPI(cfg)
	templateapi.InitPickTemplateAPI(cfg)
	custom.InitAPI(api)
	fileapi.InitAPI(api)
	superadmin.InitUser(api)
	stateapi.InitOnlineAPI(api)
	thingapi.BeginMsgSocketIO(r)
	thingapi.InitConfigAPI(cfg)
	byEdge := cfg.Group("/syncByEdge")
	byEdge.PUT("/:edgeID", createByEdge)

	/*if cfg != nil {
		cfg.Use(token.AuthMiddleware())
		logger.Log.Info("--------------TM create middleware--------------")
	}*/
	if api != nil {
		dataapi.InitDataAPI(api)
		alarmapi.InitAlarmAPI(api)
		serviceapi.InitService(api)
		maintain.InitMaintainAPI(api)
		picapi.InitPicApi(api)
		//api.Use(token.AuthMiddleware())
		file, _ := exec.LookPath(os.Args[0])
		path, err := filepath.Abs(file)
		//dir = "d:/work/node/TS/bin"
		//dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
		dir := filepath.Dir(path)
		if strings.Index(dir, "bin") < 0 {
			dir = dir + "/bin"
		}

		if err != nil {
			log.Fatal(err)
		}
		dir = dir + "/dist"
		fmt.Println("--------------------", dir)
		r.StaticFS("/static", http.Dir(dir))
		r.Static("/js", dir+"/js")
		r.Static("/css", dir+"/css")
		r.Static("/img", dir+"/img")
		r.Static("/assets", dir+"/assets")
		r.Static("/baiduOffLineMap", dir+"/baiduOffLineMap")

		r.LoadHTMLFiles(dir + "/index.html")
		r.GET("/", func(context *gin.Context) {
			context.HTML(http.StatusOK, "index.html", nil)
		})
		r.StaticFS("/ui/", http.Dir(dir))
		monitor.InitSelfPicker()
		lport := fmt.Sprintf(":%v", config.SelfOption.MaintainPort)

		//r.Use(gzip.Gzip(gzip.DefaultCompression))
		r.Run(lport)
	}

}
